package io.renren.common.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 日期工具类
 */
public class DateUtils {
    // 英文简写 如：2010-12-01
    public static final String FORMAT_SHORT = "yyyy-MM-dd";
    // 英文全称(默认) 如：2010-12-01 23:15:06
    public static final String FORMAT_LONG = "yyyy-MM-dd HH:mm:ss";
    //精确到毫秒的完整时间 如：yyyy-MM-dd HH:mm:ss.SSS
    public static final String FORMAT_FULL = "yyyy-MM-dd HH:mm:ss.SSS";

    // 以毫秒表示的时间
    private static final long DAY_IN_MILLIS = 24 * 3600 * 1000;
    private static final long HOUR_IN_MILLIS = 3600 * 1000;
    private static final long MINUTE_IN_MILLIS = 60 * 1000;
    private static final long SECOND_IN_MILLIS = 1000;

    // ////////////////////////////////////////////////////////////////////////////
    // formatShortDate
    // formatLongDate
    // getNowDate
    // getNowDateTime
    // getNow
    // format
    // 将日期对象格式化成字符串
    // ////////////////////////////////////////////////////////////////////////////

    /**
     * 返回格式化日期字符串, 如：2010-12-01
     *
     * @param date
     * @return
     */
    public static String formatShortDate(Date date) {
        return format(date, FORMAT_SHORT);
    }

    /**
     * 返回格式化日期字符串, 如：2010-12-01 23:15:06
     *
     * @param date
     * @return
     */
    public static String formatLongDate(Date date) {
        return format(date, FORMAT_LONG);
    }

    /**
     * 返回当前系统日期, 如：2010-12-01
     *
     * @return
     */
    public static String getNowDate() {
        return format(new Date(), FORMAT_SHORT);
    }

    /**
     * 返回当前系统日期时间, 如：2010-12-01 23:15:06
     *
     * @return
     */
    public static String getNowDateTime() {
        return format(new Date(), FORMAT_LONG);
    }

    /**
     * 根据用户格式返回当前系统日期或时间
     *
     * @param format
     * @return
     */
    public static String getNow(String format) {
        return format(new Date(), format);
    }

    /**
     * 返回用户格式格式化日期字符串
     *
     * @param date
     * @param pattern
     * @return
     */
    public static String format(Date date, String pattern) {
        String result = "";
        if (date != null) {
            SimpleDateFormat df = new SimpleDateFormat(pattern);
            result = df.format(date);
        }
        return (result);
    }

    // ////////////////////////////////////////////////////////////////////////////
    // getYear 获取指定日期的年份
    // getMonth 获取指定日期的月份
    // getDay 获取指定日期的天
    // ////////////////////////////////////////////////////////////////////////////

    /**
     * 获取指定日期的年份
     *
     * @param date
     * @return
     */
    public static String getYear(Date date) {
        String result = "";
        if (date != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            result = String.valueOf(cal.get(Calendar.YEAR));
        }
        return result;
    }

    /**
     * 获取指定日期的月份
     *
     * @param date
     * @return
     */
    public static String getMonth(Date date) {
        String result = "";
        if (date != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            result = String.valueOf(cal.get(Calendar.MONTH) + 1);
        }
        return result;
    }

    /**
     * 获取指定日期的天
     *
     * @param date
     * @return
     */
    public static String getDay(Date date) {
        String result = "";
        if (date != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            result = String.valueOf(cal.get(Calendar.DATE));
        }
        return result;
    }

    // ////////////////////////////////////////////////////////////////////////////
    // parseShortDate
    // parseLongDate
    // parse
    // 将字符串日期解析成日期对象
    // ////////////////////////////////////////////////////////////////////////////

    /**
     * 使用预设格式提取字符串日期, 如：2010-12-01
     *
     * @param strDate
     * @return
     */
    public static Date parseShortDate(String strDate) {
        return parse(strDate, FORMAT_SHORT);
    }

    /**
     * 使用预设格式提取字符串日期, 如：2010-12-01 23:15:06
     *
     * @param strDate
     * @return
     */
    public static Date parseLongDate(String strDate) {
        return parse(strDate, FORMAT_LONG);
    }

    /**
     * 使用用户格式提取字符串日期
     *
     * @param strDate
     * @param pattern
     * @return
     */
    public static Date parse(String strDate, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        try {
            return sdf.parse(strDate);
        } catch (ParseException e) {
            return null;
        }
    }

    // ////////////////////////////////////////////////////////////////////////////
    // addYear
    // addMonth
    // addDay
    // addMinute
    // addWeek
    // 在指定日期上增加年数、月数、天数、分钟数、周数
    // getWeekOfYear 获取指定日期是所在年的第几周
    // ////////////////////////////////////////////////////////////////////////////

    /**
     * 在指定日期上增加数个整年
     *
     * @param date
     * @param n    要增加的年数(若减少，则写成负数)
     * @return
     */
    public static Date addYear(Date date, int n) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.YEAR, n);
        return cal.getTime();
    }

    /**
     * 在指定日期上增加数个整月
     *
     * @param date
     * @param n    要增加的月数(若减少，则写成负数)
     * @return
     */
    public static Date addMonth(Date date, int n) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, n);
        return cal.getTime();
    }

    /**
     * 在指定日期上增加天数
     *
     * @param date
     * @param n    要增加的天数(若减少，则写成负数)
     * @return
     */
    public static Date addDay(Date date, int n) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, n);
        return cal.getTime();
    }

    /**
     * 在指定日期上增加分钟数
     *
     * @param date
     * @param n    要增加的分钟数(若减少，则写成负数)
     * @return
     */
    public static Date addMinute(Date date, int n) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MINUTE, n);
        return cal.getTime();
    }

    /**
     * 在指定日期上增加周数
     *
     * @param date
     * @param n    要增加的周数(若减少，则写成负数)
     * @return
     */
    public static Date addWeek(Date date, int n) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.WEEK_OF_YEAR, n);
        return cal.getTime();
    }

    /**
     * 获取指定日期是所在年的第几周
     *
     * @param date
     * @return
     */
    public static Integer getWeekOfYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setTime(date);
        int week = calendar.get(Calendar.WEEK_OF_YEAR);
        int mouth = calendar.get(Calendar.MONTH);
        // 如果月份是12月，且求出来的周数是第一周，说明该日期实质上是这一年的第53周，也是下一年的第一周
        // 如2019.12.29~2019.12.31与2020.1.1~2020.1.4是同一周，在JDK中可能会把前一年末尾的几天判定为下一年的第一周
        if (mouth >= 11 && week <= 1) {
            week += 52;
        }
        return week;
    }

    // ////////////////////////////////////////////////////////////////////////////
    // getCalendar
    // 各种方式获取日历Calendar
    // ////////////////////////////////////////////////////////////////////////////

    /**
     * 当前日历，这里用中国时间表示
     *
     * @return
     */
    public static Calendar getCalendar() {
        return Calendar.getInstance();
    }

    /**
     * 获取指定毫秒数表示的日历
     *
     * @param millis
     * @return
     */
    public static Calendar getCalendar(long millis) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date(millis));
        return cal;
    }

    /**
     * 获取指定日期表示的日历
     *
     * @param date
     * @return
     */
    public static Calendar getCalendar(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal;
    }

    // ////////////////////////////////////////////////////////////////////////////
    // getDate
    // 各种方式获取日期对象Date
    // ////////////////////////////////////////////////////////////////////////////

    /**
     * 获取当期日期对象
     *
     * @return
     */
    public static Date getDate() {
        return new Date();
    }

    /**
     * 获取指定毫秒数表示的日期
     *
     * @param millis
     * @return
     */
    public static Date getDate(long millis) {
        return new Date(millis);
    }

    // ////////////////////////////////////////////////////////////////////////////
    // getMillis
    // 各种方式获取毫秒数
    // ////////////////////////////////////////////////////////////////////////////

    /**
     * 获取系统时间的毫秒数
     *
     * @return
     */
    public static long getMillis() {
        return System.currentTimeMillis();
    }

    /**
     * 获取指定日历的毫秒数
     *
     * @param cal
     * @return
     */
    public static long getMillis(Calendar cal) {
        return cal.getTime().getTime();
    }

    /**
     * 获取指定日期的毫秒数
     *
     * @param date
     * @return
     */
    public static long getMillis(Date date) {
        return date.getTime();
    }

    // ////////////////////////////////////////////////////////////////////////////
    // dateDiff 计算两个日期之间的差值
    // getYearCha 计算两个日期之间相差的周年数
    // getMonthCha 计算两个日期之间相差的月数
    // getDayCha 计算两个日期之间相差的天数
    // countDays 按用户格式字符串计算距离今天的天数
    // between 获取两个日期相差秒值并回显某(秒/分钟/小时/天)前
    // ////////////////////////////////////////////////////////////////////////////

    /**
     * 计算两个时间之间的差值
     *
     * @param flag   计算标志，表示按照年/月/日/时/分/秒等计算
     * @param calSrc 减数
     * @param calDes 被减数
     * @return 两个日期之间的差值
     */
    public static int dateDiff(char flag, Calendar calSrc, Calendar calDes) {
        if (flag == 'y') { // 年
            return (calSrc.get(Calendar.YEAR) - calDes.get(Calendar.YEAR));
        }
        if (flag == 'M') { // 月
            return ((calSrc.get(Calendar.YEAR) - calDes.get(Calendar.YEAR)) * 12) + (calSrc.get(Calendar.MONTH) - calDes.get(Calendar.MONTH));
        }

        long millisDiff = getMillis(calSrc) - getMillis(calDes);
        if (flag == 'd') { // 天
            return (int) (millisDiff / DAY_IN_MILLIS);
        }
        if (flag == 'h') { // 小时
            return (int) (millisDiff / HOUR_IN_MILLIS);
        }
        if (flag == 'm') { // 分钟
            return (int) (millisDiff / MINUTE_IN_MILLIS);
        }
        if (flag == 's') { // 秒
            return (int) (millisDiff / SECOND_IN_MILLIS);
        }
        return 0;
    }

    /**
     * 计算两个时间之间的差值
     *
     * @param flag    计算标志，表示按照年/月/日/时/分/秒等计算
     * @param dateSrc 减数
     * @param dateDes 被减数
     * @return 两个日期之间的差值
     */
    public static int dateDiff(char flag, Date dateSrc, Date dateDes) {
        Calendar calSrc = Calendar.getInstance();
        calSrc.setTime(dateSrc);
        Calendar calDes = Calendar.getInstance();
        calDes.setTime(dateDes);
        return dateDiff(flag, calSrc, calDes);
    }

    /**
     * 计算两个日期之间相差的周年数
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int getYearCha(Date date1, Date date2) {
        return dateDiff('y', date1, date2);
    }

    /**
     * 计算两个日期之间相差的周年数
     *
     * @param dateStr1
     * @param dateStr2
     * @param pattern
     * @return
     */
    public static int getYearCha(String dateStr1, String dateStr2, String pattern) {
        Date date1 = parse(dateStr1, pattern);
        Date date2 = parse(dateStr2, pattern);
        return getYearCha(date1, date2);
    }

    /**
     * 计算两个日期之间相差的月数
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int getMonthCha(Date date1, Date date2) {
        return dateDiff('M', date1, date2);
    }

    /**
     * 计算两个日期之间相差的月数
     *
     * @param dateStr1
     * @param dateStr2
     * @param pattern
     * @return
     */
    public static int getMonthCha(String dateStr1, String dateStr2, String pattern) {
        Date date1 = parse(dateStr1, pattern);
        Date date2 = parse(dateStr2, pattern);
        return getMonthCha(date1, date2);
    }

    /**
     * 计算两个日期之间相差的天数
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int getDayCha(Date date1, Date date2) {
        return dateDiff('d', date1, date2);
    }

    /**
     * 计算两个日期之间相差的天数
     *
     * @param dateStr1
     * @param dateStr2
     * @param pattern
     * @return
     */
    public static int getDayCha(String dateStr1, String dateStr2, String pattern) {
        Date date1 = parse(dateStr1, pattern);
        Date date2 = parse(dateStr2, pattern);
        return getDayCha(date1, date2);
    }

    /**
     * 按用户格式字符串计算距离今天的天数
     *
     * @param date
     * @param format
     * @return
     */
    public static int countDays(String date, String format) {
        Calendar calSrc = Calendar.getInstance();
        Calendar calDes = Calendar.getInstance();
        calDes.setTime(parse(date, format));
        return dateDiff('d', calSrc, calDes);
    }

    /**
     * 按默认格式的字符串计算距离今天的天数, 如：2010-12-01 23:15:06
     *
     * @param date
     * @return
     */
    public static int countDays(String date) {
        return countDays(date, FORMAT_LONG);
    }

    /**
     * 获取两个日期相差秒值并回显某(秒/分钟/小时/天)前
     *
     * @param begin
     * @param end
     * @return
     */
    public static String between(Date begin, Date end) {
        String msg = "";
        long expire = dateDiff('s', begin, end);
        expire = Math.abs(expire);// 取绝对值
        if (expire < 60) {
            msg = expire + "秒前";
        } else if (expire == 60) {
            long m = expire / 60;
            msg = m + "分钟";
        } else if (expire > 60 && expire < 3600) {
            long m = expire / 60;
            msg = m + "分钟前";
        } else if (expire == 3600) {
            long h = expire / 3600;
            msg = h + "小时";
        } else if (expire > 3600 && expire < 86400) {
            long h = expire / 3600;
            msg = h + "小时前";
        } else if (expire == 86400) {
            long d = expire / 86400;
            msg = d + "天";
        } else {
            long d = expire / 86400;
            msg = d + "天前";
        }
        return msg;
    }

    /**
     * 获取两个日期相差秒值并回显某(秒/分钟/小时/天)前
     *
     * @param begin
     * @param end
     * @param format
     * @return
     */
    public static String between(String begin, String end, String format) {
        Date date1 = parse(begin, format);
        Date date2 = parse(end, format);
        return between(date1, date2);
    }

    // ////////////////////////////////////////////////////////////////////////////
    // compareDate
    // 比较日期大小
    // ////////////////////////////////////////////////////////////////////////////

    /**
     * 比较日期大小
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int compareDate(String date1, String date2) {
        return compareDate(date1, date2, FORMAT_LONG);
    }

    /**
     * 比较日期大小
     *
     * @param date1
     * @param date2
     * @param pattern
     * @return
     */
    public static int compareDate(String date1, String date2, String pattern) {
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        c1.setTime(parse(date1, pattern));
        c2.setTime(parse(date2, pattern));

        //result==0：相等
        //result<0：date1小于date2
        //result>0：date1大于date2
        int result = c1.compareTo(c2);
        return result;
    }

    // ////////////////////////////////////////////////////////////////////////////
    // dataToUpper
    // 日期转化为大写
    // ////////////////////////////////////////////////////////////////////////////

    /**
     * 日期转化为大写
     *
     * @param dateStr
     * @return
     */
    public static String dataToUpper(String dateStr) {
        String res = "";
        Date date = parse(dateStr, FORMAT_SHORT);
        if (date != null) {
            Calendar ca = Calendar.getInstance();
            ca.setTime(date);
            int year = ca.get(Calendar.YEAR);
            int month = ca.get(Calendar.MONTH) + 1;
            int day = ca.get(Calendar.DAY_OF_MONTH);
            res = numToUpper(year) + "年" + monthToUppder(month) + "月" + dayToUppder(day) + "日";
        }
        return res;
    }

    /**
     * 将数字转化为大写
     *
     * @param num
     * @return
     */
    private static String numToUpper(int num) {
        // String u[] = {"零","壹","贰","叁","肆","伍","陆","柒","捌","玖"};
        String u[] = {"〇", "一", "二", "三", "四", "五", "六", "七", "八", "九"};
        char[] str = String.valueOf(num).toCharArray();
        String rstr = "";
        for (int i = 0; i < str.length; i++) {
            rstr = rstr + u[Integer.parseInt(str[i] + "")];
        }
        return rstr;
    }

    /**
     * 月转化为大写
     *
     * @param month
     * @return
     */
    private static String monthToUppder(int month) {
        if (month < 10) {
            return numToUpper(month);
        } else if (month == 10) {
            return "十";
        } else {
            return "十" + numToUpper(month - 10);
        }
    }

    /**
     * 日转化为大写
     *
     * @param day
     * @return
     */
    private static String dayToUppder(int day) {
        if (day < 20) {
            return monthToUppder(day);
        } else {
            char[] str = String.valueOf(day).toCharArray();
            if (str[1] == '0') {
                return numToUpper(Integer.parseInt(str[0] + "")) + "十";
            } else {
                return numToUpper(Integer.parseInt(str[0] + "")) + "十" + numToUpper(Integer.parseInt(str[1] + ""));
            }
        }
    }

    // ////////////////////////////////////////////////////////////////////////////
    // getSeason 根据日期获取日期所在季度
    // getQuarterStartEndTime 根据季度数获取季度的开始时间结束时间
    // ////////////////////////////////////////////////////////////////////////////

    /**
     * 根据日期获取日期所在季度
     *
     * @param date
     * @return
     */
    public static int getSeason(Date date) {
        int season = 0;
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        int month = c.get(Calendar.MONTH);
        switch (month) {
            case Calendar.JANUARY:
            case Calendar.FEBRUARY:
            case Calendar.MARCH:
                season = 1;
                break;
            case Calendar.APRIL:
            case Calendar.MAY:
            case Calendar.JUNE:
                season = 2;
                break;
            case Calendar.JULY:
            case Calendar.AUGUST:
            case Calendar.SEPTEMBER:
                season = 3;
                break;
            case Calendar.OCTOBER:
            case Calendar.NOVEMBER:
            case Calendar.DECEMBER:
                season = 4;
                break;
            default:
                break;
        }
        return season;
    }

    /**
     * 根据季度数获取季度的开始时间结束时间
     *
     * @param quarter
     * @return
     */
    public static Map<String, Date> getQuarterStartEndTime(int quarter) {
        Map<String, Date> result = new HashMap<>();
        Calendar start = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        if (quarter == 1) {
            start.set(Calendar.MONTH, 0);
            start.set(Calendar.DATE, 1);
            end.set(Calendar.MONTH, 2);
            end.set(Calendar.DATE, 31);
        } else if (quarter == 2) {
            start.set(Calendar.MONTH, 3);
            start.set(Calendar.DATE, 1);
            end.set(Calendar.MONTH, 5);
            end.set(Calendar.DATE, 30);
        } else if (quarter == 3) {
            start.set(Calendar.MONTH, 6);
            start.set(Calendar.DATE, 1);
            end.set(Calendar.MONTH, 8);
            end.set(Calendar.DATE, 30);
        } else if (quarter == 4) {
            start.set(Calendar.MONTH, 9);
            start.set(Calendar.DATE, 1);
            end.set(Calendar.MONTH, 11);
            end.set(Calendar.DATE, 31);
        }

        start.set(Calendar.HOUR, 0);
        start.set(Calendar.MINUTE, 0);
        start.set(Calendar.SECOND, 0);
        end.set(Calendar.HOUR, 23);
        end.set(Calendar.MINUTE, 59);
        end.set(Calendar.SECOND, 59);
        result.put("startTime", start.getTime());
        result.put("endTime", end.getTime());
        return result;
    }

    /**
     * 根据时间获取季度的开始时间结束时间
     *
     * @param date
     * @return
     */
    public static Map<String, Date> getQuarterStartEndTime(Date date) {
        int quarter = getSeason(date);
        return getQuarterStartEndTime(quarter);
    }

}
